<?php
/**
 * 验证码
 */
declare(strict_types=1);

namespace App\Helper;

use App\Exception\BusinessException;
use Hyperf\Redis\RedisFactory;
use Hyperf\Utils\ApplicationContext;
use Hyperf\Utils\Str;

class CaptchaHelper
{
    const ADMIN_COOKIE_NAME = 'admin_captcha';

    const GUEST_COOKIE_NAME = 'guest_captcha';

    /**
     * 判断验证码
     * @param string $code
     * @param string $ip
     * @param int $time
     * @param string $sign
     * @param string $redisPool
     * @return bool
     */
    public static function check(string $code, string $ip, int $time, string $sign, string $redisPool = 'default'): bool
    {
        if (strlen($code) !== 4) {
            return false;
        }
        if (!$ip) {
            return false;
        }
        $now = time();
        if ($time >= $now || $now - $time > 30) {
            return false;
        }
        if (strlen($sign) !== 32) {
            return false;
        }
        if (self::genCookieValue($code, $ip, $time, true) !== $sign) {
            return false;
        }
        $redis = ApplicationContext::getContainer()->get(RedisFactory::class)->get($redisPool);
        if (!$redis) {
            return false;
        }
        return $redis->set('captcha:' . $sign, 1, ['nx', 'ex' => 60]);
    }

    /**
     * 生成Cookie值
     * @param string $code
     * @param string $ip
     * @param int $time
     * @param bool $reSign
     * @return string
     */
    public static function genCookieValue(
        string $code,
        string $ip = '0.0.0.0',
        int $time = 0,
        bool $reSign = false
    ): string {
        $time || $time = time();
        $key = env('CAPTCHA_KEY');
        if (!$key) {
            throw new BusinessException(0, '请在 .env 配置 CAPTCHA_KEY=你的KEY ！');
        }
        $sign = md5(strtolower($code) . $key . $ip . $time);
        return $reSign ? $sign : 'time=' . $time . '&sign=' . $sign;
    }

    /**
     * 生成一个
     * @return array
     */
    public static function genOne(): array
    {
        $code = Str::random(4);
        $im = imagecreate(50, 20);
        imagecolorallocate($im, 255, 255, 255);
        $text_color = imagecolorallocate($im, 0, 0, 0);
        imagestring($im, 5, 5, 4 + mt_rand(-3, 3), $code[0], $text_color);
        imagestring($im, 5, 15, 4 + mt_rand(-3, 3), $code[1], $text_color);
        imagestring($im, 5, 25, 4 + mt_rand(-3, 3), $code[2], $text_color);
        imagestring($im, 5, 35, 4 + mt_rand(-3, 3), $code[3], $text_color);
        for ($xi = 20; $xi >= 0; $xi--) {
            imagesetpixel($im, mt_rand(0, 50), mt_rand(0, 20), $text_color);
        }
        ob_start();
        imagepng($im);
        $content = ob_get_clean();
        imagedestroy($im);
        return [$code, $content];
    }
}
